/*
 * raid.c
 *
 *  Created on: 19/09/2011
 *      Author: utn_so
 */

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <pthread.h>
#include <sys/epoll.h>

#include "log.h"
#include "config.h"
#include "nipc.h"

#include "plani.h"
#include "raid.h"
#include "consola.h"
#include "fs.h"

struct descriptor_t *tablaDesc = NULL, *tablaprox;
pthread_mutex_t descriptor = PTHREAD_MUTEX_INITIALIZER;
char localip[13];
int fdConsola, cantSecTotal = 0;
struct t_sockets	*tablaSock = NULL;
int fdPoll = 0;


int main()
{
	pthread_t	idHilo;

	struct epoll_event *events;
	struct epoll_event event;
	int i, errno;
	size_t maxEvents = 20; // cualca, tiene que salir de fdmax y la cantidad de planis y consola
	int cantWait = -1;
	struct t_sockets *nodoSocket;
	int fdmax = 0, consolaActivada, fd = 0, errno;


	tablaprox = (struct descriptor_t *) malloc(sizeof(struct descriptor_t));
	tablaprox->pedidos = NULL;
	tablaprox->descriptorSoc = 0;
	tablaprox->estado = 0;
	tablaprox->idDisco = 0;
	tablaprox->siguiente = NULL;

	cargarConfig("raid.config");
	printf("cargo config \n");

	atexit(&clearConfig);
	atexit(&clearTablaSock);

	getConfig("localip", &localip);
	printf("cargo localip: %s\n", localip);


	getConfig("fdmax", &fdmax);

	fdPoll = epoll_create(fdmax + 10);

	if (fdPoll == -1) {
		printf("Error al crear el poll. Error n°: %d, descripcion: %s.\n",
				errno, strerror(errno));

		exit(1);
	}

	getConfig("consolaActivada", &consolaActivada);
	if (consolaActivada == 1) {

		fdConsola = crearSockConsola();

		pollIn(fdConsola);

		agregarFdEnTablaSock(fdConsola, P_CONSOLA);
	}

	fd = crearSockListener(fdmax);

	pollIn(fd);
	agregarFdEnTablaSock(fd, P_LISTENER);

	printf("Poll creado con exito!\n");


	events = calloc(maxEvents, sizeof(event));

	do {

		cantWait = epoll_wait(fdPoll, events, maxEvents, -1);

		if (cantWait == -1) {
			printf("Error en el wait. Error: %d, %s\n", errno, strerror(errno));

		}

		for (i = 0; i < cantWait; i++) {
			nodoSocket = tablaSock;

			while ((nodoSocket != NULL) && (nodoSocket->fd != events[i].data.fd)) {
				nodoSocket = nodoSocket->siguiente;
			}

			switch (nodoSocket->proceso) {
			case P_CONSOLA:
//					atenderConsola(nodoSocket->fd);
				break;
			case P_LISTENER:
				atenderListener(fdPoll, nodoSocket->fd);
				break;
			case P_FS:
				atenderFS(nodoSocket->fd);
				break;
			case P_PPD:
				atenderPlani(nodoSocket->fd);
				break;
			}
		}
	} while (cantWait > 0);
	free(events);




	freeTablaDesc();

	exit(0);
}


void pollIn(int fd) {
	struct epoll_event event;
	int s, errno;

	memset(&event, 0, sizeof(event));

	event.data.fd = fd;
	event.events = EPOLLIN;
	s = epoll_ctl(fdPoll, EPOLL_CTL_ADD, fd, &event);

	if (s == -1) {
		printf("Error al agregar un fd. Error n°: %d, descripcion: %s.\n", errno, strerror(errno));
		exit(1);
	}
}



int freeTablaDesc()
{
	struct descriptor_t* aux = NULL;
	aux = tablaDesc;
	while(aux != NULL)
	{
		while(aux->siguiente != NULL)
		{
			aux = aux->siguiente;
		}
		if(aux->siguiente == NULL)
		{
			free(aux);
		}
		aux = tablaDesc;
	}
	if(tablaDesc == NULL)
	{
		return 1;
	}
return 0;
}

/*
void* escucharPlaniYFS(void *params) {
	int fdmax = 0, consolaActivada, fd = 0, errno;

	getConfig("fdmax", &fdmax);

	fdPoll = epoll_create(fdmax + 10);

	if (fdPoll == -1) {
		printf("Error al crear el poll. Error n°: %d, descripcion: %s.\n",
				errno, strerror(errno));

		exit(1);
	}

	getConfig("consolaActivada", &consolaActivada);
	if (consolaActivada == 1) {

		fdConsola = crearSockConsola();

		pollIn(fdConsola);

		agregarFdEnTablaSock(fdConsola, P_CONSOLA);
	}

	fd = crearSockListener(fdmax);

	pollIn(fd);
	agregarFdEnTablaSock(fd, P_LISTENER);

	printf("Poll creado con exito!\n");

	atenderPoll();

	return NULL;
}
*/


/*void escucharConsola(void)
{
	struct sockaddr_un 		dir;
	int 				fdCon, *fdParam = NULL, retval;
	pthread_t			tid;
	nipcMessage			msg;
	char *				CONSOLA_HANDSHAKE = NULL;
	int					consolita = 0, h = 0;


	dir.sun_family = AF_UNIX;
	strcpy(dir.sun_path, "/tmp/raid.temp");

	fdConsola = socket(AF_UNIX, SOCK_STREAM, 0);

	if(0 > bind(fdConsola, (struct sockaddr*)&dir, sizeof(dir)))
	{
		retval = errno;
		if(retval == EADDRINUSE)
		{
			system("rm /tmp/raid.temp");
			if(0 > bind(fdConsola, (struct sockaddr*)&dir, sizeof(dir)))
			{
				perror("bind");
				exit(1);
			}
		} else {
			perror("bind");
			exit(1);
		}
	}


	listen(fdConsola, 50);

	while(1)
	{
		fdCon = accept(fdConsola, NULL, NULL);

		// handhake

		retval = nipc_recv(&msg, fdCon);

		sprintf(CONSOLA_HANDSHAKE, "%d", consola_handshake);

		h = strncmp(msg.payload, CONSOLA_HANDSHAKE, 2);

		if ((retval == NIPC_ERROR) || (msg.payloadLength == 0) || (!h))
		{

			printf("error de handshake");
			nipc_0payload(&msg, fdCon);
			sprintf(msg.payload, "%d", HANDSHAKE_FAIL);
			msg.payloadLength = strlen(msg.payload) + 1;
			msg.type = '0';

			nipc_send(&msg, fdCon);
			close(fdCon);
		}
		else
		{

			sprintf(msg.payload,"%d;%d", consolita, HANDSHAKE_OK);

			msg.payloadLength = strlen(msg.payload) + 1;

			//todo agregar al descriptor_t

			// Mandamos la respuesta del handshake
			nipc_send(&msg, fdCon);

		fdParam = (int *) malloc(sizeof (int)); //todo hacer free

		*fdParam = fdCon;

		pthread_create(&tid, NULL, atenderConsola, (void*)fdParam);
		free(fdParam); //todo ver si esta bien aca
		}
	}

}*/

void cerrarSocketShell()
{
	close(fdConsola);
	system("rm /tmp/raid.temp");
}


void clearTablaSock()
{
	free(tablaSock);
}
